package com.ciwong.mobilelib.widget.listview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

import com.ciwong.libs.utils.CWLog;
import com.ciwong.mobilelib.R;
import com.ciwong.mobilelib.i.ViewOnClickListener;

import java.lang.reflect.Method;

/**
 * 带滑动删除的LinearLayout
 *
 * @author res-jianpingliu
 *
 */
@SuppressLint("NewApi")
public class SlideView extends LinearLayout implements OnGestureListener
{

    /**
     * 两次点击时间间隔
     */
    private final long duration = 1000;

    /**
     * 挤压的时间
     */
    private final int collapseDuration = 400;

    /**
     * 左右滑动的弹力
     */
    private final int tan = 3;

    /**
     * 如果滑出来的部分有一半的宽度那么在up事件里面会自动滑到最大宽度
     */
    private final float half = 0.25f;

    private LinearLayout mViewContent, mSlideLayout;

    private Scroller mScroller;

    private OnSlideClickListener mSlideClickListener;

    private OnSlideListener mOnSlideListener;

    private SlideItemOnClickListener mItemOnClickListener;

    private int defaultWidth = 0;

    /**
     * 默认是一个宽度
     */
    private int mHolderWidth = 0;

    private int mLastX = 0;

    private int mLastY = 0;

    private ISlideListView mSlideListView;

    private TextView mDeleteText, mText1;

    private int position = AdapterView.INVALID_POSITION;

    /**
     * 滑动状态值
     */
    private int mStatus;

    /**
     * 自定义的手势监听器(修改了onShowPress的时间为60，系统值为180)
     */
    private GestureDetector mDetector;

    /**
     * item的高度
     */
    private int mHeight;

    /**
     * 是否可挤压
     */
    private boolean collapseScrollAble;

    /**
     * 是否需要挤压（如果需要删除item，那么推荐用挤压效果）
     */
    private boolean needCollapse;

    /**
     * 如果两个按钮的效果都需要挤压，需要加一个标记用来标记是否点击的是删除按钮
     */
    private boolean isClickDelete;

    /**
     * 阀门值：用来判断滑动的标准
     */
    private int mSlop;

    private boolean mSlideEnable;

    private SlideSwitch slideSwitch;

    /**
     * 上一次点击时间
     */
    private long lastClickTime;

    /**
     * 点击item时是否有press的效果
     */
    private boolean isPressed = true;

    private boolean isDerectCollapse;

    private boolean showDeleteAnim = false;

    /**
     * 滑动开头
     *
     * @author res-jianpingliu
     */
    public interface SlideSwitch
    {

        /**
         * 是否可以滑动
         *
         * @param view
         *            当前操作的view
         * @param position
         *            当前操作的view在listView中的索引
         * @param id
         *            view的id
         * @return true:允许滑动
         */
        boolean isSlideEnable(SlideView view, int position, long id);
    }

    /**
     * 滑动状态监听
     *
     * @author res-jianpingliu
     *
     */
    public interface OnSlideListener
    {
        /**
         * 关闭
         */
        public static final int SLIDE_STATUS_OFF = 0;

        /**
         * 开始
         */
        public static final int SLIDE_STATUS_ING = 1;

        /**
         * 完全显示
         */
        public static final int SLIDE_STATUS_ON = 2;

        /**
         * 滑动状态回调
         *
         * @param view
         *            当前操作的view
         * @param position
         *            当前操作的view在listView中的索引
         * @param status
         *            状态
         */
        public void onSlide(SlideView view, int position, int status);
    }

    /**
     * 滑动出来的View点击监听
     *
     * @author res-jianpingliu
     *
     */
    public interface OnSlideClickListener
    {
        /**
         * 执行第一个view的点击事件
         *
         * @param position
         *            listview中的下标(已去掉了header的数量)
         * @param v
         *            当前的操作的view
         */
        public void performSecondViewOnClick(int position, View v);

        /**
         * 执行第二个view的点击事件
         *
         * @param position
         *            listview中的下标(已去掉了header的数量)
         * @param v
         *            当前的操作的view
         * @param isDerectCollapse
         *            是否直接挤压
         */
        public void performFirstViewOnClick(int position, View v, boolean isDerectCollapse);
    }

    /**
     * 滑动删除listView的adapter的bean类需要实现的接口，并且该bean需要有一个SlideView成员变量
     *
     * @author res-jianpingliu
     *
     */
    public interface SlideItem
    {
        /**
         * 获得当前操作的view
         *
         * @return 操作的view
         */
        public SlideView getSlideView();
    }

    /**
     * SlideView在列表中的点击事件
     */
    public interface SlideItemOnClickListener
    {
        /**
         * onClick回调方法
         *
         * @param slideView
         *            当前操作的view
         * @param position
         *            当前操作的下标
         */
        void onClick(SlideView slideView, int position);
    }

    /**
     * 带滑动删除的LinearLayout
     *
     * @param context
     *            上下文
     */
    public SlideView(Context context)
    {
        super(context);
        initView(context);
    }

    /**
     * 带滑动删除的LinearLayout
     *
     * @param context
     *            上下文
     * @param attrs
     *            属性
     *
     */
    public SlideView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        initView(context);
    }

    /**
     * 带滑动删除的LinearLayout
     *
     * @param context
     *            上下文
     * @param attrs
     *            属性
     * @param defStyle
     *            样式
     */
    public SlideView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        initView(context);
    }

    @Override
    public boolean onDown(MotionEvent e)
    {
        // CWLog.e("ljp", "onDown ... SlideListView.isSlide() = " +
        // mSlideListView.isSlide());
        if (!mScroller.isFinished())
        {
            mScroller.abortAnimation();
        }

        return true;
    }

    @Override
    public void onShowPress(MotionEvent e)
    {
        // CWLog.e("ljp", "onShowPress ... ");
        if (mStatus != OnSlideListener.SLIDE_STATUS_OFF)
        {
            shrink();
        }
        else
        {
            setPressed(true);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void setPressed(boolean pressed)
    {
        // CWLog.w("ljp", "setPressed = " + pressed);
        super.setPressed(pressed);
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e)
    {
        // CWLog.e("ljp", "onSingleTapUp ... ");

        if (mSlideListView != null
                && mSlideListView.getSlideStatus() == OnSlideListener.SLIDE_STATUS_ON)
        {
            mSlideListView.shrink();
            return true;
        }

        if (/* hasPressed && */mSlideListView != null
                && position > AdapterView.INVALID_POSITION
                && mStatus == OnSlideListener.SLIDE_STATUS_OFF
                && vertifyDuration())
        {
            setPressed(isPressed);
            // CWLog.e("ljp", "performItemClick ... ");

            if (mItemOnClickListener != null)
            {
                mItemOnClickListener.onClick(this,
                        position - mSlideListView.getHeaderViewsCount());
            }
        }
        return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                            float distanceY)
    {
        setStatus(OnSlideListener.SLIDE_STATUS_ING);
        // float detaY = Math.abs(distanceY);
        // CWLog.e("ljp", "onScroll ... distanceY =  " + distanceY);
        return true;
    }

    @Override
    public void onLongPress(MotionEvent e)
    {
        // CWLog.e("ljp", "onLongPress ... ");
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                           float velocityY)
    {
        // CWLog.e("ljp", "onFling ... ");
        return super.onTouchEvent(e2);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        /*if (mSlideLayout.getChildCount() == 1)
        {
            mHolderWidth = defaultWidth / 2;
        }*/
        int x = (int) event.getX();
        int y = (int) event.getY();
        int scrollX = getScrollX();
        // CWLog.e("ljp", "item onTouchEvent ..." + event.getAction() +
        // " , scrollX = " + scrollX);
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
            {
                // CWLog.e("ljp", "item ACTION_DOWN ...");
                if (slideSwitch != null)
                {
                    mSlideEnable = slideSwitch.isSlideEnable(SlideView.this,
                            position - mSlideListView.getHeaderViewsCount(),
                            getId());
                }

                break;
            }
            case MotionEvent.ACTION_MOVE:
            {
                setPressed(false);
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                /*
                 * if (Math.abs(deltaX) < Math.abs(deltaY) * tan) { break; }
                 */
                // 滑动时需要大过阀门值
                if (mSlop < deltaX)
                {
                    break;
                }
                int newScrollX = scrollX - deltaX;

                if (deltaX != 0)
                {
                    // 最少不能小于0
                    if (newScrollX < 0)
                    {
                        newScrollX = 0;
                    }
                    else if (newScrollX > mHolderWidth)
                    {
                        // 最多不能超过mHolderWidth
                        newScrollX = mHolderWidth;
                    }
                    // SlideView根据手势动作左右滑动到相应位置
                    if (scrollX < 0)
                    {
                        break;
                    }
                    // 在点击后的一秒种内不让滑动
                    if (mSlideEnable)
                    {
                        this.scrollTo(newScrollX, 0);
                    }

                }
                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            {
                setPressed(false);
                if (mSlideEnable)
                {
                    upScrollTo();
                }
                break;
            }
        }

        mLastX = x;
        mLastY = y;
        return mDetector.onTouchEvent(event);
    }

    @Override
    public void computeScroll()
    {
        float scrollX = getScrollX();
        // float scrollY = getScrollY();
        // CWLog.w("ljp", "scrollX = " + scrollX);
        if (mScroller.computeScrollOffset())
        {
            // 如果可以挤压那么执行挤压
            if (collapseScrollAble)
            {
                verticalCollapse();
                // 挤压是纵向滑动效果，所以此时不执行横向滑动
                return;
            }

            if (mSlideEnable)
            {
                horizontalScroll();
            }
        }

    }

    /**
     * 执行up事件后的滑动操作
     */
    public void upScrollTo()
    {
        int scrollX = getScrollX();
        int newScrollX = 0;
        // 如果滑动的距离>mHolderWidth的一半，那么认为此次动作是要开启滑动，否则是回到原点
        if (scrollX - mHolderWidth * half >= 0)
        {
            newScrollX = mHolderWidth;
        }
        // 松开手指，要么滑动到开启状态，要么还原到初始状态，只有这两种情况
        smoothScrollTo(newScrollX, 0);
    }

    public void setShowDeleteAnim(boolean show)
    {
        showDeleteAnim = show;
    }

    /**
     * 滑动还原
     *
     */
    public void shrink()
    {
        if (getScrollX() != 0)
        {
            this.smoothScrollTo(0, 0);
        }
        else
        {
            // CWLog.e("ljp", "SlideView shrink scrollx = 0");
            setStatus(OnSlideListener.SLIDE_STATUS_OFF);
            mSlideListView.setSlideStatus(OnSlideListener.SLIDE_STATUS_OFF);
        }
    }

    /**
     * 准备挤压
     *
     * @param derectCollapse
     *            是否直接挤压
     */
    public void prepareCollapse(boolean derectCollapse)
    {
        isDerectCollapse = derectCollapse;
        collapseScrollAble = true;
        if (!mScroller.isFinished())
        {
            mScroller.abortAnimation();
        }
        // CWLog.d("ljp", "slideUp");
        mScroller.startScroll(0, mHeight, 0, -mHeight, collapseDuration);
        invalidate();
    }

    /**
     * 慢滑到某个位置
     *
     * @param destX
     *            目标位置x坐标
     * @param destY
     *            目标位置y坐标
     */
    private void smoothScrollTo(int destX, int destY)
    {
        // 缓慢滚动到指定位置
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * tan);
        invalidate();
    }

    /**
     * 横向滑动
     */
    private void horizontalScroll()
    {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

        // 如果横向偏移量等于holder的宽度，那么表示是开启状态，
        if (mScroller.getCurrX() == mHolderWidth)
        {
            setStatus(OnSlideListener.SLIDE_STATUS_ON);
        }
        // 如果横向偏移量等于0，那么表示是关闭状态，
        else if (mScroller.getCurrX() == 0)
        {
            setStatus(OnSlideListener.SLIDE_STATUS_OFF);
        }
        // 其他状态是正在滑动状态
        else
        {
            setStatus(OnSlideListener.SLIDE_STATUS_ING);
        }

        postInvalidate();
    }

    /**
     * 设置当前的横向滑动状态
     *
     * @param status
     *            状态 {@link OnSlideListener}
     */
    public void setStatus(int status)
    {
        if (mStatus != status)
        {
            mStatus = status;
            onStateChanged(status);
        }
    }

    public int getStatus()
    {
        return mStatus;
    }

    /**
     * 状态改变
     *
     * @param status
     *            状态 {@link OnSlideListener}
     */
    public void onStateChanged(int status)
    {
        switch (status)
        {
            case OnSlideListener.SLIDE_STATUS_OFF:
                onSlideOff();
                break;
            case OnSlideListener.SLIDE_STATUS_ING:
                onSliding();
                break;
            case OnSlideListener.SLIDE_STATUS_ON:
                onSlideOn();
                break;
        }
        if (mOnSlideListener != null)
        {
            mOnSlideListener.onSlide(this,
                    position - mSlideListView.getHeaderViewsCount(), status);
        }
    }

    /**
     * 滑动到完全展开状态
     */
    private void onSlideOn()
    {
        // CWLog.e("ljp", "SLIDE_STATUS_ON");
        if (mSlideListView != null)
        {
            mSlideListView.setLastSlideView(this);
            mSlideListView.setSlideStatus(OnSlideListener.SLIDE_STATUS_ON);
        }
    }

    /**
     * 正在滑动状态
     */
    private void onSliding()
    {
        // CWLog.w("ljp", "SLIDE_STATUS_ING");
        if (mSlideListView != null)
        {
            mSlideListView.setLastSlideView(this);
            mSlideListView.setSlideStatus(OnSlideListener.SLIDE_STATUS_ING);
        }
    }

    /**
     * 滑动到完全关闭状态
     */
    private void onSlideOff()
    {
        // CWLog.w("ljp", "SLIDE_STATUS_OFF");
        if (mSlideListView != null)
        {
            mSlideListView.setLastSlideView(this);
            mSlideListView.setSlideStatus(OnSlideListener.SLIDE_STATUS_OFF);
        }
    }

    public void setISlideListView(ISlideListView listView)
    {
        mSlideListView = listView;
    }

    /**
     * 设置当前操作的对象所处listview中的下标
     *
     * @param pos
     *            下标
     */
    public void setSelectPosition(int pos)
    {
        position = pos;
    }

    public void setOnSlideClickListener(OnSlideClickListener osll)
    {
        mSlideClickListener = osll;
    }

    /**
     * 设置listview的item布局
     *
     * @param view
     *            item
     */
    public void setContentView(View view)
    {
        mViewContent.addView(view);
    }

    public View getContentView()
    {
        return mViewContent;
    }

    /**
     * 设置滑动监听
     *
     * @param onSlideListener
     *            滑动监听
     */
    public void setOnSlideListener(OnSlideListener onSlideListener)
    {
        mOnSlideListener = onSlideListener;
    }

    /**
     *
     * 设置 onClick监听
     *
     * @param itemOnClickListener
     *            onClick监听
     */
    public void setSlideItemOnClickListener(
            SlideItemOnClickListener itemOnClickListener)
    {
        mItemOnClickListener = itemOnClickListener;
    }

    /**
     *
     * 设置 第一个view显示的字符
     *
     * @param str
     *            显示的字符
     */
    public void setFirstViewText(CharSequence str)
    {
        mText1.setText(str);
        setSlideLayoutParams();
    }

    /**
     * 设置第二个显示的字符
     *
     * @param strId
     *            显示的字符
     */
    public void setSecondViewText(int strId)
    {
        mDeleteText.setText(strId);
        setSlideLayoutParams();
    }

    /**
     *
     * 设置 第一个view显示的字符
     *
     * @param str
     *            显示的字符
     */
    public void setFirstViewText(int str)
    {
        mText1.setText(str);
        setSlideLayoutParams();
    }

    /**
     * 隐藏第二按钮的图标
     */
    public void hideDrawDelete()
    {
        mDeleteText.setCompoundDrawables(null, null, null, null);
        setSlideLayoutParams();
    }

    /**
     * 隐藏滑出部分的第一个view
     */
    public void hideFirstView()
    {
        mText1.setVisibility(View.GONE);
        setSlideLayoutParams();
    }

    /**
     * 显示滑出部分的第一个view
     *
     * @param need
     *            是否需要挤压效果
     */
    public void showFirstView(boolean need)
    {
        needCollapse = need;
        mText1.setVisibility(View.VISIBLE);
        setSlideLayoutParams();
    }

    public void hideSecondView()
    {
        mDeleteText.setVisibility(View.GONE);
        setSlideLayoutParams();
    }

    public void setSlideSwitch(SlideSwitch ss)
    {
        slideSwitch = ss;
    }

    public void setSlideEnable(boolean enable)
    {
        mSlideEnable = enable;
    }

    public boolean isPressed()
    {
        return isPressed;
    }

    public void setIsPressed(boolean isPressed)
    {
        this.isPressed = isPressed;
    }

    private void initView(Context context)
    {
        mSlop = ViewConfiguration.get(context).getScaledTouchSlop();

        mScroller = new Scroller(getContext());

        setOrientation(LinearLayout.HORIZONTAL);
        View.inflate(getContext(), R.layout.widget_slide_view, this);
        // listView的item显示的内容
        mViewContent = (LinearLayout) findViewById(R.id.slide_view_content);
        // 隐藏的layout
        mSlideLayout = (LinearLayout) findViewById(R.id.slide_view_slideLayout);

        mText1 = (TextView) findViewById(R.id.slide_text1);
        mDeleteText = (TextView) findViewById(R.id.delete);

        mText1.setOnClickListener(new ViewOnClickListener()
        {
            @Override
            public void avertRepeatOnClick(View v)
            {
                if (mSlideClickListener != null)
                {
                    mSlideClickListener.performFirstViewOnClick(position
                                    - mSlideListView.getHeaderViewsCount(),
                            SlideView.this, false);
                }
            }
        });

        mDeleteText.setOnClickListener(new ViewOnClickListener()
        {
            @Override
            public void avertRepeatOnClick(View v)
            {
                if (showDeleteAnim)
                {
                    mSlideClickListener.performSecondViewOnClick(position
                                    - mSlideListView.getHeaderViewsCount(),
                            SlideView.this);
                    return;
                }
                isClickDelete = true;
                prepareCollapse(true);
            }
        });

        getViewTreeObserver().addOnGlobalLayoutListener(
                new OnGlobalLayoutListener()
                {

                    @Override
                    public void onGlobalLayout()
                    {
                        removeObser(this);
                        setSlideLayoutParams();
                    }
                });

        mDetector = new GestureDetector(getContext(), this);

        mViewContent.setOnTouchListener(new OnTouchListener()
        {

            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                if (mStatus == OnSlideListener.SLIDE_STATUS_ON)
                {
                    shrink();
                    return true;
                }
                return false;
            }
        });

        // hideFirstView();
    }

    private void setSlideLayoutParams()
    {
        mSlideLayout.measure(MeasureSpec.makeMeasureSpec(
                        ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(
                        ViewGroup.LayoutParams.WRAP_CONTENT,
                        MeasureSpec.UNSPECIFIED));
        mHolderWidth = mSlideLayout.getMeasuredWidth();
        mHeight = mSlideLayout.getMeasuredHeight();

        LayoutParams params = (LayoutParams) mSlideLayout.getLayoutParams();
        params.width = mHolderWidth;
        mSlideLayout.setLayoutParams(params);
    }

    private void removeObser(OnGlobalLayoutListener lis)
    {
        if (Integer.parseInt(Build.VERSION.SDK) < 16)
        {
            getViewTreeObserver().removeGlobalOnLayoutListener(lis);
        }
        else
        {
            try
            {
                Method downPolymorphic = getViewTreeObserver().getClass()
                        .getMethod("removeOnGlobalLayoutListener",

                                new Class[]{OnGlobalLayoutListener.class});
                if (downPolymorphic != null)
                {
                    downPolymorphic.invoke(getViewTreeObserver(),
                            new Object[]{lis});
                }
            }
            catch (Exception e)
            {
                getViewTreeObserver().removeGlobalOnLayoutListener(lis);
                CWLog.e("ljp", "SlideView removeObser Exception");
            }

        }
    }

    /**
     * 执行挤压(原理是根据scroller计算并设置item的高度)
     */
    private void verticalCollapse()
    {
        int height = mScroller.getCurrY();
        ViewGroup.LayoutParams lp = getLayoutParams();
        lp.height = height;
        // CWLog.d("ljp", "computeScroll:" + lp.height + "      height:" +
        // height);
        setLayoutParams(lp);
        if (height == 0)
        {
            collapseScrollAble = false;
            if (mSlideClickListener != null)
            {
                // 回调业务操作
                SlideHolder sh = (SlideHolder) getTag();
                if (sh != null)
                {
                    sh.needInflate = true;

                    if (mSlideListView != null)
                    {
                        mSlideListView
                                .setSlideStatus(OnSlideListener.SLIDE_STATUS_OFF);
                    }

                    // 如果是点击删除按钮，那么执行第二个点击操作
                    if (isClickDelete)
                    {
                        mSlideClickListener.performSecondViewOnClick(position
                                        - mSlideListView.getHeaderViewsCount(),
                                SlideView.this);
                    }
                    else
                    {
                        // 如果只是需要压缩，不需要回调那么不用执行这个方法
                        mSlideClickListener.performFirstViewOnClick(position
                                        - mSlideListView.getHeaderViewsCount(),
                                SlideView.this, isDerectCollapse);
                    }
                    // }
                }
            }
            // 如果高度为0了表示，挤压工作完成了, 那么不需要刷新了
            return;
        }
        postInvalidate();
    }

    /**
     * 验证两次点击时间差
     *
     * @return 是否验证通过
     */
    private boolean vertifyDuration()
    {
        long tmpTime = System.currentTimeMillis();
        if (tmpTime - lastClickTime <= duration && tmpTime - lastClickTime > 0)
        {
            return false;
        }
        lastClickTime = System.currentTimeMillis();
        return true;
    }
}
